package models

import (
	"context"
	"database/sql"
	"errors"
	"fmt"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
	"message/common"
	"strings"
	"time"
)

var _ MessageAggregationModel = (*customMessageAggregationModel)(nil)

type (
	MessageAggregationModel interface {
		messageAggregationModel
	}

	customMessageAggregationModel struct {
		conn               sqlx.SqlConn
		messageModel       defaultMessageModel
		messageStatusModel defaultMessageStatusModel
	}
)

func NewMessageAggregationModel(conn sqlx.SqlConn) MessageAggregationModel {
	return &customMessageAggregationModel{
		conn: conn,
	}
}

type (
	messageAggregationModel interface {
		CreateMessage(ctx context.Context, message *Message, receiverIds []int64) error
		UpdateMessage(ctx context.Context, msgId, senderId, status int64) error
		ReadMessage(ctx context.Context, receiverType, receiverID, userId, status int64) error
		GetMessageCount(ctx context.Context, senderId, receiverType, receiverId, userId, status int64) (int64, map[int64]int64, map[int64]int64, error)
		GetMessageList(ctx context.Context, senderId, receiverType, receiverId, userId, status int64, lastMsgId, limit int64) ([]*Message, error)
	}
)

// CreateMessage 创建消息
func (m *customMessageAggregationModel) CreateMessage(ctx context.Context, msg *Message, receiverIds []int64) error {
	// 用事务包裹所有操作，确保消息和状态要么同时成功，要么同时失败
	return m.conn.TransactCtx(ctx, func(ctx context.Context, session sqlx.Session) error {
		// 1. 插入消息主表
		messageInsertSQL := fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s, ?, ?, ?, ?, ?, ?, ?, ?)", m.messageModel.table, "`id`", messageRowsExpectAutoSet)

		// 执行消息插入
		result, err := session.ExecCtx(
			ctx, messageInsertSQL, msg.Id, msg.SenderId, msg.ReceiverType, msg.ReceiverId,
			msg.ContentType, msg.Content, msg.FileName, msg.FileSize, msg.Status,
		)
		if err != nil {
			return fmt.Errorf("消息插入失败: %w", err)
		}

		// 获取插入的消息ID
		msgId, err := result.LastInsertId()
		if err != nil {
			return fmt.Errorf("获取消息ID失败: %w", err)
		}

		// 2. 插入消息状态表（区分单聊/群聊）
		switch msg.ReceiverType {
		case common.ReceiverTypeSingle:
			// 单聊：插入一条状态记录
			statusInsertSQL := fmt.Sprintf("INSERT INTO %s (%s) VALUES (?, ?, ?, ?)", m.messageStatusModel.table, messageStatusRowsExpectAutoSet)

			_, err := session.ExecCtx(ctx, statusInsertSQL, msgId, msg.ReceiverId, common.MessageNotRead)
			if err != nil {
				return fmt.Errorf("单聊状态插入失败: %w", err)
			}

		case common.ReceiverTypeGroup:
			// 构建批量插入SQL
			var placeholders []string
			var args []interface{}
			for _, uid := range receiverIds {
				placeholders = append(placeholders, "(?, ?, ?, ?)")
				args = append(args, msgId, uid, common.MessageNotRead, "NULL")
			}

			statusBatchInsertSQL := fmt.Sprintf(
				"INSERT INTO %s (%s) VALUES %s",
				m.messageStatusModel.table,
				messageStatusFieldNames,
				strings.Join(placeholders, ","),
			)

			// 执行批量插入
			_, err := session.ExecCtx(ctx, statusBatchInsertSQL, args...)
			if err != nil {
				return fmt.Errorf("群聊状态批量插入失败: %w", err)
			}

		default:
			return errors.New("无效的接收者类型")
		}

		return nil
	})
}

// UpdateMessage 撤回/删除消息
func (m *customMessageAggregationModel) UpdateMessage(ctx context.Context, msgId, senderId, status int64) error {
	return m.conn.TransactCtx(ctx, func(ctx context.Context, session sqlx.Session) error {
		var msg Message
		selectQuery := fmt.Sprintf("SELECT * FROM %s WHERE id = ? and sender_id = ?", m.messageModel.table)
		err := session.QueryRowCtx(ctx, &msg, selectQuery, msgId, senderId)
		if err != nil {
			return err
		}
		// 非自己发送的消息不能撤回
		if msg.SenderId != senderId {
			return errors.New("非自己发送的消息不能撤回")
		}

		// 超过时间限制的消息不能撤回
		if time.Since(msg.CreatedAt) > common.MessageRecallTimeLimit {
			return errors.New("消息已过期，不能撤回")
		}

		updateQuery := fmt.Sprintf("UPDATE %s SET status = ? WHERE id = ?", m.messageModel.table)
		_, err = session.ExecCtx(ctx, updateQuery, common.MessageRecall, msg.Id)
		if err != nil {
			return err
		}

		updateStatusQuery := fmt.Sprintf("UPDATE %s SET status = ? WHERE msg_id = ?", m.messageStatusModel.table)
		_, err = session.ExecCtx(ctx, updateStatusQuery, common.MessageHasDeleted, msg.Id)
		if err != nil {
			return err
		}
		return nil
	})
}

// ReadMessage 已读消息
func (m *customMessageAggregationModel) ReadMessage(ctx context.Context, receiverType, receiverID, userId, status int64) error {
	return m.conn.TransactCtx(ctx, func(ctx context.Context, session sqlx.Session) error {
		// 1. 查找未读消息标识
		var (
			msgIDs       []int64
			placeholders []string
			args         []interface{}
		)
		selectQuery := fmt.Sprintf("SELECT a.id FROM %s as a join %s as b on a.id = b.msg_id "+
			"WHERE a.receiver_type = ? AND a.receiver_id = ? AND a.status = ? and b.user_id = ?",
			m.messageModel.table, m.messageStatusModel.table)
		err := session.QueryRowsCtx(ctx, &msgIDs, selectQuery, receiverType, receiverID, common.MessageNotRead, userId)
		if err != nil {
			return err
		}
		// 2. 更新消息状态
		for _, msgId := range msgIDs {
			placeholders = append(placeholders, "?")
			args = append(args, msgId)
		}
		placeholder := strings.Join(placeholders, ",")
		readTime := sql.NullTime{Valid: true, Time: time.Now()}
		updateSql := fmt.Sprintf("UPDATE %s SET read_status = ?, read_time = ? WHERE id in (%s) and user_id = ?",
			m.messageModel.table, placeholder)
		_, err = session.ExecCtx(ctx, updateSql, status, readTime, msgIDs, userId)
		if err != nil {
			return err
		}
		return nil
	})
}

// GetMessageCount 获取消息数量
func (m *customMessageAggregationModel) GetMessageCount(ctx context.Context, senderId, receiverType, receiverId, userId, status int64) (int64, map[int64]int64, map[int64]int64, error) {
	var (
		total     int64
		singleMap = make(map[int64]int64)
		groupMap  = make(map[int64]int64)
	)
	type CountMap struct {
		ReceiverType int64
		ReceiverId   int64
		Total        int64
	}
	var countMap []CountMap
	query := fmt.Sprintf(
		"select a.receiver_type, a.receiver_id, sum(b.id) as total from message_status as a "+
			"join message as b on a.msg_id = b.id where a.user_id = %d and a.read_status = %d ", userId, status,
	)
	if senderId != 0 {
		query += fmt.Sprintf(" and b.sender_id = %d", senderId)
	}
	if receiverType != 0 {
		query += fmt.Sprintf(" and b.receiver_type = %d", receiverType)
	}
	if receiverId != 0 {
		query += fmt.Sprintf(" and b.receiver_id = %d", receiverId)
	}
	query += " group by a.receiver_type, a.receiver_id order by b.create_at"
	err := m.conn.QueryRowsCtx(ctx, &countMap, query)
	if err != nil {
		return 0, nil, nil, err
	}

	for _, item := range countMap {
		switch item.ReceiverType {
		case common.ReceiverTypeSingle:
			singleMap[item.ReceiverId] = item.Total
		case common.ReceiverTypeGroup:
			groupMap[item.ReceiverId] = item.Total
		}
		total += item.Total
	}
	return total, singleMap, groupMap, nil
}

// GetMessageList 获取消息列表
func (m *customMessageAggregationModel) GetMessageList(ctx context.Context, senderId, receiverType, receiverId, userId, status, lastMsgId, limit int64) ([]*Message, error) {
	var msgIDs []int64
	query := fmt.Sprintf(
		"select a.msg_id from %s as a join %s as b on a.msg_id = b.id where a.user_id = %d and a.read_status = %d ",
		m.messageStatusModel.table, m.messageModel.table, userId, status,
	)
	if senderId != 0 {
		query += fmt.Sprintf(" and b.sender_id = %d", senderId)
	}
	if receiverType != 0 {
		query += fmt.Sprintf(" and b.receiver_type = %d", receiverType)
	}
	if receiverId != 0 {
		query += fmt.Sprintf(" and b.receiver_id = %d", receiverId)
	}
	query += fmt.Sprintf(" and b.id < %d order by b.create_at desc limit %d", lastMsgId, limit)
	err := m.conn.QueryRowsCtx(ctx, &msgIDs, query)
	if err != nil {
		return nil, err
	}

	var (
		msgList      []*Message
		placeholders []string
		args         []interface{}
	)
	for _, msgId := range msgIDs {
		placeholders = append(placeholders, "?")
		args = append(args, msgId)
	}
	listQuery := fmt.Sprintf("select * from %s where id in (%s)", m.messageModel.table, strings.Join(placeholders, ","))
	err = m.conn.QueryRowsCtx(ctx, &msgList, listQuery, args...)
	if err != nil {
		return nil, err
	}
	return nil, nil
}
